﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using RuYiAdmin.Net.Common.Global;
using RuYiAdmin.Net.Common.Utility;
using RuYiAdmin.Net.Entity.BusinessEnum;
using RuYiAdmin.Net.Service.BusinessService.Redis;
using RuYiAdmin.Net.WebApi.AppCode.Base;
using RuYiAdmin.Net.WebApi.AppCode.Filter;
using RuYiAdmin.Net.WebApi.AppCode.JWT;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace RuYiAdmin.Net.WebApi.Controllers.Jwt
{
    /// <summary>
    /// JWT接口认证
    /// </summary>
    [ApiController]
    [Route(GlobalContext.RouteTemplate)]
    public class AuthenticateController : ControllerBase
    {
        private readonly IRedisService redis;

        /// <summary>
        /// 构造函数
        /// </summary>
        public AuthenticateController(IRedisService redis)
        {
            this.redis = redis;
        }

        /// <summary>
        /// 获取盐
        /// </summary>
        /// <returns>盐</returns>
        [HttpGet]
        [AllowAnonymous]
        [Log(OperationType.QueryList)]
        public async Task<IActionResult> Get(String userName)
        {
            if (String.IsNullOrEmpty(userName))
            {
                return BadRequest("user name can not be null");
            }

            if (userName.Equals(GlobalContext.JwtSettings.DefaultUser))
            {
                var salt = Guid.NewGuid();
                var encrytStr = Md5Util.Encrypt(GlobalContext.JwtSettings.DefaultPassword, salt);
                await redis.SetAsync(salt.ToString(), encrytStr, GlobalContext.JwtSettings.SaltExpiration);
                var actionResult = new RuYiAdmin.Net.Entity.CoreEntity.ActionResult()
                {
                    HttpStatusCode = HttpStatusCode.OK,
                    Object = salt,
                    Message = "获取成功"
                };
                return Ok(actionResult);
            }

            return NoContent();
        }

        /// <summary>
        /// JWT身份认证接口
        /// </summary>
        /// <param name="jwtAuthentication">身份信息</param>
        /// <returns>token信息</returns>
        [HttpPost]
        [AllowAnonymous]
        public IActionResult Post([FromBody] JwtAuthentication jwtAuthentication)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState.ValidationState);
            }

            var encrytStr = String.Empty;

            if (redis.Exists(new string[] { jwtAuthentication.Salt }) > 0)
            {
                encrytStr = redis.Get(jwtAuthentication.Salt);
            }

            if (String.IsNullOrEmpty(encrytStr))
            {
                return BadRequest("Salt Is Not Validated");
            }

            if (jwtAuthentication.UserName.Equals(GlobalContext.JwtSettings.DefaultUser) && jwtAuthentication.Password.Equals(encrytStr))
            {
                redis.Delete(new string[] { jwtAuthentication.Salt });

                //创建claim
                var authClaims = new[] {
                    new Claim(JwtRegisteredClaimNames.Sub,jwtAuthentication.UserName),
                    new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
               };

                IdentityModelEventSource.ShowPII = true;

                //签名秘钥 
                var ecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(GlobalContext.JwtSettings.SecurityKey));

                var token = new JwtSecurityToken(
                       issuer: GlobalContext.JwtSettings.Issuer,
                       audience: GlobalContext.JwtSettings.Audience,
                       expires: DateTime.Now.AddMinutes(GlobalContext.JwtSettings.TokenExpiration),
                       claims: authClaims,
                       signingCredentials: new SigningCredentials(ecurityKey, SecurityAlgorithms.HmacSha256)
                       );

                var actionResult = new RuYiAdmin.Net.Entity.CoreEntity.ActionResult()
                {
                    HttpStatusCode = HttpStatusCode.OK,
                    Object = new JwtSecurityTokenHandler().WriteToken(token),
                    Message = "获取成功,expiration:" + token.ValidTo.ToLocalTime()
                };
                return Ok(actionResult);
            }

            return NotFound();
        }
    }
}
